home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / SMTPCLI.C < prev    next >
C/C++ Source or Header  |  1989-09-07  |  21KB  |  929 lines

  1. /*
  2.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <time.h>
  16. #include <setjmp.h>
  17. #ifdef UNIX
  18. #include <sys/types.h>
  19. #endif
  20. #ifdef    __TURBOC__
  21. #include <dir.h>
  22. #include <io.h>
  23. #endif
  24. #include "global.h"
  25. #ifdef    ANSIPROTO
  26. #include <stdarg.h>
  27. #endif
  28. #include "mbuf.h"
  29. #include "cmdparse.h"
  30. #include "proc.h"
  31. #include "socket.h"
  32. #include "timer.h"
  33. #include "netuser.h"
  34. #include "smtp.h"
  35. #include "dirutil.h"
  36.  
  37. extern char Badhost[];
  38.  
  39. static struct timer smtpcli_t;
  40. static int32 gateway;
  41.  
  42. #ifdef SMTPTRACE
  43. static int Smtptrace = 0;            /* used for trace level */
  44. static int dosmtptrace();
  45. #endif
  46.  
  47. static unsigned  short smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  48. static int smtpsessions = 0;        /* number of client connections
  49.                     * currently open */
  50. int    Smtpmode = 0;
  51.  
  52. static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  53.  
  54. static char quitcmd[] = "QUIT\r\n";
  55. static char eom[] = "\r\n.\r\n";
  56.  
  57. static void abort_trans __ARGS((struct smtpcli *cb));
  58. static void del_job __ARGS((struct smtp_job *jp));
  59. static void del_session __ARGS((struct smtpcli *cb));
  60. static int dogateway __ARGS((int argc,char *argv[],void *p));
  61. static int dosmtpmaxcli __ARGS((int argc,char *argv[],void *p));
  62. static int dotimer __ARGS((int argc,char *argv[],void *p));
  63. static void execjobs __ARGS((void));
  64. static void logerr __ARGS((struct smtpcli *cb));
  65. static struct smtpcli *lookup __ARGS((int32 destaddr));
  66. static struct smtpcli *newcb __ARGS((void));
  67. static int next_job __ARGS((struct smtpcli *cb));
  68. static void retmail __ARGS((struct smtpcli *cb));
  69. static void sendcmd __ARGS((struct smtpcli *cb,char *fmt,...));
  70. static int sendfile __ARGS((struct smtpcli *cb));
  71. static void sendquit __ARGS((struct smtpcli *cb));
  72. static int setsmtpmode __ARGS((int argc,char *argv[],void *p));
  73. static struct smtp_job *setupjob __ARGS((struct smtpcli *cb,char *id,char *from));
  74. static void smtp_send __ARGS((int unused,void *cb1,void *p));
  75. static int smtpkick __ARGS((int argc,char *argv[],void *p));
  76.  
  77. static struct cmds Smtpcmds[] = {
  78.     "gateway",    dogateway,    0,    0,    NULLCHAR,
  79.     "mode",        setsmtpmode,    0,    0,    NULLCHAR,
  80.     "kick",        smtpkick,    0,    0,    NULLCHAR,
  81.     "maxclients",    dosmtpmaxcli,    0,    0,    NULLCHAR,
  82.     "timer",    dotimer,    0,    0,    NULLCHAR,
  83. #ifdef SMTPTRACE
  84.     "trace",    dosmtptrace,    0,    0,    NULLCHAR,
  85. #endif
  86.     NULLCHAR,
  87. };
  88.  
  89. int
  90. dosmtp(argc,argv,p)
  91. int argc;
  92. char *argv[];
  93. void *p;
  94. {
  95.     return subcmd(Smtpcmds,argc,argv,p);
  96. }
  97.  
  98. static int
  99. dosmtpmaxcli(argc,argv,p)
  100. int argc;
  101. char *argv[];
  102. void *p;
  103. {
  104.     return setshort(&smtpmaxcli,"Max clients",argc,argv);
  105. }
  106.  
  107. static int
  108. setsmtpmode(argc,argv,p)
  109. int argc;
  110. char *argv[];
  111. void *p;
  112. {
  113.     if (argc < 2) {
  114.         printf("smtp mode: %s\n",
  115.             (Smtpmode & QUEUE) ? "queue" : "route");
  116.     } else {
  117.         switch(*argv[1]) {
  118.         case 'q':
  119.             Smtpmode |= QUEUE;
  120.             break;
  121.         case 'r':
  122.             Smtpmode &= ~QUEUE;
  123.             break;
  124.         default:
  125.             printf("Usage: smtp mode [queue | route]\n");
  126.             break;
  127.         }
  128.     }
  129.     return 0;
  130. }
  131. static int
  132. dogateway(argc,argv,p)
  133. int argc;
  134. char *argv[];
  135. void *p;
  136. {
  137.     int32 n;
  138.  
  139.     if(argc < 2){
  140.         printf("%s\n",inet_ntoa(gateway));
  141.     } else if((n = resolve(argv[1])) == 0){
  142.         printf(Badhost,argv[1]);
  143.         return 1;
  144.     } else
  145.         gateway = n;
  146.     return 0;
  147. }
  148.  
  149. #ifdef SMTPTRACE
  150. static int
  151. dosmtptrace(argc,argv,p)
  152. int argc;
  153. char *argv[];
  154. void *p;
  155. {
  156.     return setbool(&Smtptrace,"SMTP tracing",argc,argv);
  157. }
  158. #endif
  159.  
  160. /* Set outbound spool scan interval */
  161. static int
  162. dotimer(argc,argv,p)
  163. int argc;
  164. char *argv[];
  165. void *p;
  166. {
  167.     if(argc < 2){
  168.         printf("%lu/%lu\n",
  169.         (smtpcli_t.start - smtpcli_t.count)/(1000/MSPTICK),
  170.         smtpcli_t.start/(1000/MSPTICK));
  171.         return 0;
  172.     }
  173.     smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
  174.     smtpcli_t.arg = NULL;        /* dummy value */
  175.     smtpcli_t.start = atol(argv[1])*(1000/MSPTICK);    /* set timer duration */
  176.     start_timer(&smtpcli_t);        /* and fire it up */
  177.     return 0;
  178. }
  179.  
  180. static int
  181. smtpkick(argc,argv,p)
  182. int argc;
  183. char *argv[];
  184. void *p;
  185. {
  186.     smtptick(NULL);
  187.     return 0;
  188. }
  189.  
  190. /* This is the routine that gets called every so often to do outgoing
  191.  * mail processing. When called with a null argument, it runs the entire
  192.  * queue; if called with a specific non-zero IP address from the remote
  193.  * kick server, it only starts up sessions to that address.
  194.  */
  195. int
  196. smtptick(t)
  197. void *t;
  198. {
  199.     register struct smtpcli *cb;
  200.     struct smtp_job *jp;
  201.     struct list *ap;
  202.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  203.     char    from[LINELEN], to[LINELEN];
  204.     char *cp, *cp1;
  205.     int32 destaddr,target;
  206.     FILE *wfile;
  207.  
  208.     target = (int32)t;
  209. #ifdef SMTPTRACE
  210.     if (Smtptrace > 5)
  211.         printf("smtp daemon entered, target = %s\n",inet_ntoa(target));
  212. #endif
  213.     for(filedir(Mailqueue,0,wfilename);wfilename[0] != '\0';
  214.         filedir(Mailqueue,1,wfilename)){
  215.  
  216.         /* save the prefix of the file name which it job id */
  217.         cp = wfilename;
  218.         cp1 = prefix;
  219.         while (*cp && *cp != '.')
  220.             *cp1++ = *cp++;
  221.         *cp1 = '\0';
  222.  
  223.         /* lock this file from the smtp daemon */
  224.         if (mlock(Mailqdir,prefix))
  225.             continue;
  226.  
  227.         sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
  228.         if ((wfile = fopen(tmpstring,READ_TEXT)) == NULLFILE) {
  229.             /* probably too many open files */
  230.             (void) rmlock(Mailqdir,prefix);
  231.             /* continue to next message. The failure
  232.             * may be temporary */
  233.             continue;
  234.         }
  235.  
  236.         (void) fgets(tmpstring,LINELEN,wfile);    /* read target host */
  237.         rip(tmpstring);
  238.  
  239.         if ((destaddr = mailroute(tmpstring)) == 0) {
  240.             fclose(wfile);
  241.             printf("** smtp: Unknown address %s\n",tmpstring);
  242.             (void) rmlock(Mailqdir,prefix);
  243.             continue;
  244.         }
  245.         if(target != 0 && destaddr != target){
  246.             fclose(wfile);
  247.             (void) rmlock(Mailqdir,prefix);
  248.             continue;    /* Not the proper target of a kick */
  249.         }
  250.         if ((cb = lookup(destaddr)) == NULLSMTPCLI) {
  251.             /* there are enough processes running already */
  252.             if (smtpsessions >= smtpmaxcli) {
  253. #ifdef SMTPTRACE
  254.                 if (Smtptrace) {
  255.                     printf("smtp daemon: too many processes\n");
  256.                 }
  257. #endif
  258.                 fclose(wfile);
  259.                 (void) rmlock(Mailqdir,prefix);
  260.                 break;
  261.             }
  262.             if ((cb = newcb()) == NULLSMTPCLI) {
  263.                 fclose(wfile);
  264.                 (void) rmlock(Mailqdir,prefix);
  265.                 break;
  266.             } 
  267.             cb->ipdest = destaddr;
  268.         } else {
  269.             /* This system is already is sending mail lets not
  270.             * interfere with its send queue.
  271.             */
  272.             if (cb->state != CLI_INIT_STATE) {
  273.                 fclose(wfile);
  274.                 (void) rmlock(Mailqdir,prefix);
  275.                 continue;
  276.             }
  277.         }
  278.  
  279.         (void) fgets(from,LINELEN,wfile);    /* read from */
  280.         rip(from);
  281.         if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  282.             fclose(wfile);
  283.             (void) rmlock(Mailqdir,prefix);
  284.             del_session(cb);
  285.             break;
  286.         }
  287.         while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  288.             rip(to);
  289.             if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  290.                 fclose(wfile);
  291.                 del_session(cb);
  292.             }
  293.         }
  294.         fclose(wfile);
  295. #ifdef SMTPTRACE
  296.         if (Smtptrace > 1) {
  297.             printf("queue job %s From: %s To:",prefix,from);
  298.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  299.                 printf(" %s",ap->val);
  300.             printf("\n");
  301.         }
  302. #endif
  303.     }
  304.  
  305.     /* start sending that mail */
  306.     execjobs();
  307.  
  308.     /* Restart timer */
  309.     start_timer(&smtpcli_t);
  310.     return 0;
  311. }
  312.  
  313. /* this is the master state machine that handles a single SMTP transaction */
  314. /* it is called with a queue of jobs for a particular host. */
  315. static void
  316. smtp_send(unused,cb1,p)
  317. int unused;
  318. void *cb1;
  319. void *p;
  320. {
  321.     register struct smtpcli *cb;
  322.     register char reply;
  323.     register struct list *tp;
  324.     struct sockaddr_in fsocket;
  325.     struct mbuf *bp,*bpl;
  326.     char *cp;
  327.     char tbuf[LINELEN];
  328.     int rcode;
  329.  
  330.     cb = (struct smtpcli *)cb1;
  331.     fsocket.sin_family = AF_INET;
  332.     fsocket.sin_addr.s_addr = cb->ipdest;
  333.     fsocket.sin_port = IPPORT_SMTP;
  334.  
  335.     cb->s = socket(AF_INET,SOCK_STREAM,0);
  336.     cb->state = CLI_OPEN_STATE;    /* init state placeholder */
  337. #ifdef SMTPTRACE
  338.     if (Smtptrace) 
  339.         printf("SMTP client Trying...\n");
  340. #endif
  341.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == 0){
  342. #ifdef SMTPTRACE
  343.     if (Smtptrace) 
  344.         printf("Connected\n");
  345. #endif
  346.         ;
  347.     } else {
  348.         cp = sockerr(cb->s);
  349. #ifdef SMTPTRACE
  350.         if (Smtptrace) 
  351.             printf("Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  352. #endif
  353.         log(cb->s,"Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  354.     }
  355.  
  356.     while(1) {
  357.         
  358.         if (recvline(cb->s,cb->buf,LINELEN) == -1)
  359.             goto quit;
  360.         rip(cb->buf);
  361. #ifdef SMTPTRACE
  362.         if (Smtptrace)
  363.             printf("smtp rcvd: '%s'\n",cb->buf);
  364. #endif
  365.  
  366.         /* Another line follows, ignore this one */
  367.         if(cb->buf[0] == '0' || cb->buf[3] == '-')
  368.             continue;
  369.  
  370.         reply = cb->buf[0];
  371.         rcode = atoi(cb->buf);
  372.  
  373.         /* if service shuting down */
  374.         if (rcode == 421) {
  375.             sendquit(cb);
  376.             continue;
  377.         }
  378.  
  379.         switch(cb->state) {
  380.         case CLI_OPEN_STATE:
  381.             if (reply != '2')
  382.                 sendquit(cb);
  383.             else {
  384.                 cb->state = CLI_HELO_STATE;
  385.                 sendcmd(cb,"HELO %s\r\nMAIL FROM:<%s>\r\n",
  386.                 Hostname,cb->jobq->from);
  387.             }
  388.             break;
  389.         case CLI_HELO_STATE:
  390.             if (reply != '2')
  391.                 sendquit(cb);
  392.             else 
  393.                 cb->state = CLI_MAIL_STATE;
  394.             break;            
  395.         case CLI_MAIL_STATE:
  396.             if (reply != '2')
  397.                 sendquit(cb);
  398.             else {
  399.                 cb->state = CLI_RCPT_STATE;
  400.                 cb->rcpts = 0;
  401.                 bpl = NULLBUF;
  402.                 for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  403.                     sprintf(tbuf,"RCPT TO:<%s>\r\n",tp->val);
  404.                     bp = qdata(tbuf,(int16)strlen(tbuf));
  405.                     if (bp == NULLBUF) {
  406.                         free_p(bpl);
  407.                         sendquit(cb);
  408.                         goto quit;
  409.                     }
  410.                     append(&bpl,bp);
  411.                     cb->rcpts++;
  412. #ifdef SMTPTRACE
  413.                     if (Smtptrace) {
  414.                         printf("smtp sent: %s",tbuf);
  415.                     }
  416. #endif
  417.                 }
  418.                 send_mbuf(cb->s,bpl,0,NULLCHAR,0);
  419.             }
  420.             break;
  421.         case CLI_RCPT_STATE:
  422.             if (reply == '5') {
  423.                 logerr(cb);
  424.             } else if (reply == '2') {
  425.                 cb->goodrcpt = 1;
  426.             } else {
  427.                 /* some kind of temporary failure */
  428.                 abort_trans(cb);
  429.                 break;
  430.             }
  431.             /* if more rcpts stay in this state */
  432.             if (--cb->rcpts != 0)
  433.                 break;
  434.  
  435.             /* check for no good rcpt on the list */
  436.             if (cb->goodrcpt == 0) {
  437.                 if (cb->errlog != NULLLIST)
  438.                     retmail(cb);
  439.                 (void) unlink(cb->wname);    /* unlink workfile */
  440.                 (void) unlink(cb->tname);    /* unlink text */
  441.                 abort_trans(cb);
  442.                 break;
  443.             }
  444.             /* if this file open fails abort */
  445.             if ((cb->tfile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  446.                 abort_trans(cb);
  447.             else {
  448.                 sendcmd(cb,"DATA\r\n");
  449.                 cb->state = CLI_SEND_STATE;
  450.             }
  451.             break;
  452.         case CLI_SEND_STATE:
  453.             if (reply == '3') {
  454.                 cb->state = CLI_UNLK_STATE;
  455.                 sendfile(cb);
  456.             } else {
  457.                 sendquit(cb);
  458.             }
  459.             break;
  460.         case CLI_UNLK_STATE:
  461.             /* if a good transfer or permanent failure remove job */
  462.             if (reply == '2' || reply == '5') {
  463.                 if (reply == '5')
  464.                     logerr(cb);
  465.                 /* close and unlink the textfile */
  466.                 if(cb->tfile != NULLFILE) {
  467.                     fclose(cb->tfile);
  468.                     cb->tfile = NULLFILE;
  469.                 }
  470.                 if (cb->errlog != NULLLIST)
  471.                     retmail(cb);
  472.                 (void) unlink(cb->tname);
  473.                 (void) unlink(cb->wname);    /* unlink workfile */
  474.                 log(cb->s,"SMTP sent job %s To: %s From: %s",
  475.                 cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  476.             }
  477.             if (next_job(cb)) {
  478.                 cb->state = CLI_MAIL_STATE;
  479.                 sendcmd(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  480.             } else {
  481.                 sendquit(cb);
  482.                 cb->state = CLI_QUIT_STATE;
  483.             }
  484.             break;
  485.         case CLI_IDLE_STATE:    /* used after a RSET and more mail to send */
  486.             if (reply != '2')
  487.                 sendquit(cb);
  488.             else {
  489.                 cb->state = CLI_MAIL_STATE;
  490.                 sendcmd(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  491.             }
  492.             break;            
  493.         case CLI_QUIT_STATE:
  494.             goto quit;
  495.         }
  496.     }
  497. quit:
  498.     (void) close_s(cb->s);
  499.     if(cb->tfile != NULLFILE)
  500.         fclose(cb->tfile);
  501.     del_session(cb);
  502. }
  503.  
  504. /* abort the currrent job.
  505.  * If more work exists set up the next job if
  506.  * not then shut down.
  507. */
  508. static void
  509. abort_trans(cb)
  510. register struct smtpcli *cb;
  511. {
  512. #ifdef SMTPSTRACE
  513.     if (Smtptrace)
  514.         printf("smtpcli: abort transaction\n");
  515. #endif
  516.     if(cb->tfile != NULLFILE) {
  517.         fclose(cb->tfile);
  518.         cb->tfile = NULLFILE;
  519.     }
  520.     if (next_job(cb)) {
  521.         sendcmd(cb,"RSET\r\n");
  522.         cb->state = CLI_IDLE_STATE;
  523.     } else 
  524.         sendquit(cb);
  525. }
  526.  
  527. static void
  528. sendquit(cb)
  529. struct smtpcli *cb;
  530. {
  531.     cb->state = CLI_QUIT_STATE;
  532.     sendcmd(cb,quitcmd);    /* issue a quit command */
  533. }
  534.  
  535. /* Send message back to server */
  536. #if    defined(ANSIPROTO) && !defined(AMIGA)
  537. static void
  538. sendcmd(struct smtpcli *cb,char *fmt,...)
  539. {
  540.     va_list ap;
  541.     struct mbuf *bp;
  542.     char tmpstring[256];
  543.  
  544.     va_start(ap,fmt);
  545.  
  546. #ifdef SMTPTRACE
  547.     if (Smtptrace) {
  548.         printf("smtp sent: ");
  549.         vprintf(fmt,ap);
  550.     }
  551. #endif
  552.     vsprintf(tmpstring,fmt,ap);
  553.     va_end(ap);
  554.     bp = qdata(tmpstring,(int16)strlen(tmpstring));
  555.     send_mbuf(cb->s,bp,0,NULLCHAR,0);
  556. }
  557. #else
  558. static void
  559. sendcmd(cb,fmt,arg1,arg2)
  560. struct smtpcli *cb;
  561. char *fmt,*arg1,*arg2;
  562. {
  563.     struct mbuf *bp;
  564.     char tmpstring[256];
  565.  
  566. #ifdef SMTPTRACE
  567.     if (Smtptrace) {
  568.         printf("smtp sent: ");
  569.         printf(fmt,arg1,arg2);
  570.     }
  571. #endif
  572.     sprintf(tmpstring,fmt,arg1,arg2);
  573.     bp = qdata(tmpstring,(int16)strlen(tmpstring));
  574.     send_mbuf(cb->s,bp,0,NULLCHAR,0);
  575. }
  576. #endif
  577. /* create mail lockfile */
  578. int
  579. mlock(dir,id)
  580. char *dir,*id;
  581. {
  582.     char lockname[LINELEN];
  583.     int fd;
  584.  
  585.     /* Try to create the lock file in an atomic operation */
  586.     sprintf(lockname,"%s/%s.lck",dir,id);
  587.     if((fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT,0600)) == -1)
  588.         return -1;
  589.     close(fd);
  590.     return 0;
  591. }
  592.  
  593. /* remove mail lockfile */
  594. int
  595. rmlock(dir,id)
  596. char *dir,*id;
  597. {
  598.     char lockname[LINELEN];
  599.     sprintf(lockname,"%s/%s.lck",dir,id);
  600.     return(unlink(lockname));
  601. }
  602.  
  603. /* free the message struct and data */
  604. static void
  605. del_session(cb)
  606. register struct smtpcli *cb;
  607. {
  608.     register struct smtp_job *jp,*tp;
  609.     register int i;
  610.  
  611.     if (cb == NULLSMTPCLI)
  612.         return;
  613.     for(i=0; i<MAXSESSIONS; i++) 
  614.         if(cli_session[i] == cb) {
  615.             cli_session[i] = NULLSMTPCLI;
  616.             break;
  617.         }
  618.  
  619.     free(cb->wname);
  620.     free(cb->tname);
  621.     for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  622.             tp = jp->next;
  623.             del_job(jp);
  624.     }
  625.     del_list(cb->errlog);
  626.     free((char *)cb);
  627.     smtpsessions--;    /* number of connections active */
  628. }
  629.  
  630. static void
  631. del_job(jp)
  632. register struct smtp_job *jp;
  633. {
  634.     if ( *jp->jobname != '\0')
  635.         (void) rmlock(Mailqdir,jp->jobname);
  636.     free(jp->from);
  637.     del_list(jp->to);
  638.     free((char *)jp);
  639. }
  640.  
  641. /* delete a list of list structs */
  642. void
  643. del_list(lp)
  644. struct list *lp;
  645. {
  646.     register struct list *tp, *tp1;
  647.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  648.             tp1 = tp->next;
  649.             free(tp->val);
  650.             free((char *)tp);
  651.     }
  652. }
  653.  
  654. /* return message to sender */
  655. static void
  656. retmail(cb)
  657. struct smtpcli *cb;
  658. {
  659.     register struct list *lp;
  660.     register FILE *tfile;
  661.     register int c;
  662.     FILE *infile;
  663.     char *to;
  664.     time_t t;
  665.     
  666. #ifdef SMTPTRACE
  667.     if (Smtptrace > 5) {
  668.         printf("smtp job %s returned to sender\n",cb->wname);
  669.     }
  670. #endif
  671.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  672.     to = cb->jobq->from;
  673.     if (*to == '\0')
  674.         return;
  675.     if ((infile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  676.         return;
  677.     if ((tfile = tmpfile()) == NULLFILE) {
  678.         fclose(infile);
  679.         return;
  680.     }
  681.     time(&t);
  682.     fprintf(tfile,"Date: %s",ptime(&t));
  683.     fprintf(tfile,"Message-Id: <%ld@%s>\n",get_msgid(),Hostname);
  684.     fprintf(tfile,"From: MAILER-DAEMON@%s\n",Hostname);
  685.     fprintf(tfile,"To: %s\n",to);
  686.     fprintf(tfile,"Subject: Failed mail\n\n");
  687.     fprintf(tfile,"  ===== transcript follows =====\n\n");
  688.  
  689.     for (lp = cb->errlog; lp != NULLLIST; lp = lp->next)
  690.         fprintf(tfile,"%s\n",lp->val);
  691.  
  692.     fprintf(tfile,"\n  ===== Unsent message follows ====\n");
  693.  
  694.     while((c = getc(infile)) != EOF)
  695.         if (putc(c,tfile) == EOF)
  696.             break;
  697.     fclose(infile);
  698.     fseek(tfile,0L,0);
  699.     (void) mailuser(tfile,"",to);
  700.     fclose(tfile);
  701. }
  702.  
  703. /* look to see if a smtp control block exists for this ipdest */
  704. static struct smtpcli *
  705. lookup(destaddr)
  706. int32 destaddr;
  707. {
  708.     register int i;
  709.  
  710.     for(i=0; i<MAXSESSIONS; i++) {
  711.         if (cli_session[i] == NULLSMTPCLI)
  712.             continue;
  713.         if(cli_session[i]->ipdest == destaddr)
  714.             return cli_session[i];
  715.     }
  716.     return NULLSMTPCLI;
  717. }
  718.  
  719. /* create a new  smtp control block */
  720. static struct smtpcli *
  721. newcb()
  722. {
  723.     register int i;
  724.     register struct smtpcli *cb;
  725.  
  726.     for(i=0; i<MAXSESSIONS; i++) {
  727.         if(cli_session[i] == NULLSMTPCLI) {
  728.             cb = (struct smtpcli *)calloc(1,sizeof(struct smtpcli));
  729.             if (cb == NULLSMTPCLI)
  730.                 return(NULLSMTPCLI);
  731.             cb->wname = malloc((unsigned)strlen(Mailqdir)+JOBNAME);
  732.             if (cb->wname == NULLCHAR) {
  733.                 free((char *)cb);
  734.                 return(NULLSMTPCLI);
  735.             }
  736.             cb->tname = malloc((unsigned)strlen(Mailqdir)+JOBNAME);
  737.             if (cb->tname == NULLCHAR) {
  738.                 free(cb->wname);
  739.                 free((char *)cb);
  740.                 return(NULLSMTPCLI);
  741.             }
  742.             cb->state = CLI_INIT_STATE;
  743.             cli_session[i] = cb;
  744.             smtpsessions++;    /* number of connections active */
  745.             return(cb);
  746.         }
  747.     }
  748.     return NULLSMTPCLI;
  749. }
  750.  
  751. static void
  752. execjobs()
  753. {
  754.     register struct smtpcli *cb;
  755.     register int i;
  756.  
  757.     for(i=0; i<MAXSESSIONS; i++) {
  758.         cb = cli_session[i];
  759.         if (cb == NULLSMTPCLI) 
  760.             continue;
  761.         if(cb->state != CLI_INIT_STATE)
  762.             continue;
  763.  
  764.         sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
  765.         sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
  766.  
  767.         newproc("smtp_send", 1024, smtp_send, 0, cb,NULL);
  768.  
  769. #ifdef SMTPTRACE
  770.         if (Smtptrace) 
  771.             printf("Trying Connection to %s\n",inet_ntoa(cb->ipdest));
  772. #endif
  773.  
  774.  
  775.     }
  776. }
  777.     
  778. /* add this job to control block queue */
  779. static struct smtp_job *
  780. setupjob(cb,id,from)
  781. struct smtpcli *cb;
  782. char *id,*from;
  783. {
  784.     register struct smtp_job *p1,*p2;
  785.  
  786.     p1 = (struct smtp_job *)calloc(1,sizeof(struct smtp_job));
  787.     if (p1 == NULLJOB)
  788.         return NULLJOB;
  789.     p1->from = malloc((unsigned)strlen(from) + 1);
  790.     if (p1->from == NULLCHAR) {
  791.         free((char *)p1);
  792.         return NULLJOB;
  793.     }
  794.     strcpy(p1->from,from);
  795.     strcpy(p1->jobname,id);
  796.     /* now add to end of jobq */
  797.     if ((p2 = cb->jobq) == NULLJOB)
  798.         cb->jobq = p1;
  799.     else {
  800.         while(p2->next != NULLJOB)
  801.             p2 = p2->next;
  802.         p2->next = p1;
  803.     }
  804.     return p1;
  805. }
  806.  
  807. /* called to advance to the next job */
  808. static int
  809. next_job(cb)
  810. register struct smtpcli *cb;
  811. {
  812.     register struct smtp_job *jp;
  813.  
  814.     jp = cb->jobq->next;
  815.     del_job(cb->jobq);
  816.     if (jp == NULLJOB) {
  817.         cb->jobq = NULLJOB;
  818.         return 0;
  819.     }
  820.     /* remove the error log of previous message */
  821.     del_list(cb->errlog);
  822.     cb->errlog = NULLLIST;
  823.     cb->goodrcpt = 0;
  824.     cb->jobq = jp;
  825.     sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
  826.     sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
  827. #ifdef SMTPTRACE
  828.     if (Smtptrace > 5) {
  829.         printf("sending job %s\n",jp->jobname);
  830.     }
  831. #endif
  832.         return 1;
  833.  
  834. }
  835.  
  836.  
  837. /* mail routing funtion. For now just used the hosts file */
  838. int32
  839. mailroute(dest)
  840. char *dest;
  841. {
  842.     int32 destaddr;
  843.  
  844.     /* look up address or use the gateway */
  845.     if ((destaddr = resolve(dest)) == 0)
  846.         if (gateway != 0) 
  847.             destaddr = gateway; /* Use the gateway  */
  848.     return destaddr;
  849.     
  850. }
  851.  
  852. /* save error reply for in error list */
  853. static void
  854. logerr(cb)
  855. struct smtpcli *cb;
  856. {
  857.     register struct list *lp,*tp;
  858.     if ((tp = (struct list *)calloc(1,sizeof(struct list))) == NULLLIST)
  859.         return;
  860.     if ((tp->val = malloc((unsigned)strlen(cb->buf)+1)) == NULLCHAR) {
  861.         free((char *)tp);
  862.         return;
  863.     }
  864.     /* find end of list */
  865.     if ((lp = cb->errlog) == NULLLIST)
  866.         cb->errlog = tp;
  867.     else {
  868.         while(lp->next != NULLLIST)
  869.             lp = lp->next;
  870.         lp->next = tp;
  871.     }
  872.     strcpy(tp->val,cb->buf);
  873. }
  874.  
  875. static int
  876. sendfile(cb)
  877. register struct smtpcli *cb;
  878. {
  879.     register int c;
  880.     char *cp;
  881.     register struct mbuf *bp;
  882.     int sawnl = 1;
  883.     int error = 0;
  884.  
  885.     for(;;) {
  886.         /* Hard to know what to do here */
  887.         if ((bp = alloc_mbuf(BUFSIZ)) == NULLBUF)
  888.             return EOF;
  889.         cp = bp->data;
  890.         while(bp->cnt < BUFSIZ-2 && (c = fgetc(cb->tfile)) != EOF){
  891.             if (c == '\r')    /* strip cr from some pc hosts */
  892.                 continue;
  893.             if (c == '\n') { /* send line end as \r\n */
  894.                 *cp++ = '\r';
  895.                 bp->cnt++;
  896.                 sawnl = 1;
  897.             } else {
  898.         /* special case of a line with just a . sent as ..  one it */
  899.                 if (c == '.' && sawnl) {
  900.                     c = fgetc(cb->tfile);
  901.                     if ( c != EOF && c != '\n' && c != '\r')
  902.                         ungetc(c,cb->tfile);
  903.                     else {
  904.                         *cp++ = '.';
  905.                         bp->cnt++;
  906.                     }
  907.                     c = '.';
  908.                 }
  909.                 sawnl = 0;
  910.             }
  911.             *cp++ = c;
  912.             bp->cnt++;
  913.         }                
  914.         if(bp->cnt != 0) {
  915.             if(send_mbuf(cb->s,bp,0,NULLCHAR,0) == -1){
  916.                 error = 1;
  917.                 break;
  918.             }
  919.         } else {
  920.             free_p(bp);
  921.             break;
  922.         }
  923.     }
  924.     fclose(cb->tfile);
  925.     cb->tfile = NULLFILE;
  926.     sendcmd(cb,eom);
  927.     return error;
  928. }
  929.